﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for SubstitutionMatrix
/// </summary>
public class SubstitutionMatrix
{
    public Dictionary<string, float> matrix;

    public bool errorWhenNotInMatrix = true;
    public float gapExistPenalty;
    public float gapExtendPenalty;
    public float highestScore;
    public float lowestScore;
    /// <summary>
    /// Get the default substitution matrix for nucleotide sequences with standard values for scoreHit, mismatchPenality, gapExistPenality and gapExtendPenality
    /// </summary>
   /// <returns>a substitution matrix having the specified characteristics, can be used in Smith-Waterman or Needleman-Wunsch implementations</returns>
	public SubstitutionMatrix()
	{
        float scoreHit = 1F;
        float mismatchPenaltyBaseSubstitution= 1F;
        float gapExistPenalty = 5;
        float gapExtendPenalty = 1;
        float scoreNX = 0;

        if (scoreHit <= 0 || mismatchPenaltyBaseSubstitution <= 0) throw new ArgumentOutOfRangeException("Please specify meangingfull hit-scores and mismatch penalties for the substitution matrix");
        Dictionary<string, float> matrix = new Dictionary<string, float>();
        matrix.Add("AA", scoreHit);
        matrix.Add("AT", -mismatchPenaltyBaseSubstitution);
        matrix.Add("AC", -mismatchPenaltyBaseSubstitution);
        matrix.Add("AG", -mismatchPenaltyBaseSubstitution);
        matrix.Add("AN", scoreNX);

        matrix.Add("TA", -mismatchPenaltyBaseSubstitution);
        matrix.Add("TT", scoreHit);
        matrix.Add("TC", -mismatchPenaltyBaseSubstitution);
        matrix.Add("TG", -mismatchPenaltyBaseSubstitution);
        matrix.Add("TN", scoreNX);

        matrix.Add("CA", -mismatchPenaltyBaseSubstitution);
        matrix.Add("CT", -mismatchPenaltyBaseSubstitution);
        matrix.Add("CC", scoreHit);
        matrix.Add("CG", -mismatchPenaltyBaseSubstitution);
        matrix.Add("CN", scoreNX);

        matrix.Add("GA", -mismatchPenaltyBaseSubstitution);
        matrix.Add("GT", -mismatchPenaltyBaseSubstitution);
        matrix.Add("GC", -mismatchPenaltyBaseSubstitution);
        matrix.Add("GG", scoreHit);
        matrix.Add("GN", scoreNX);

        matrix.Add("NA", scoreNX);
        matrix.Add("NT", scoreNX);
        matrix.Add("NC", scoreNX);
        matrix.Add("NG", scoreNX);
        matrix.Add("NN", scoreNX);

        this.matrix = matrix;
        this.gapExistPenalty = gapExistPenalty;
        this.gapExtendPenalty = gapExtendPenalty;
        this.highestScore = scoreHit;
        this.lowestScore = -mismatchPenaltyBaseSubstitution;

	}

    public SubstitutionMatrix(Dictionary<string, float> matrix)
    {
        this.matrix = matrix;
    }

    public SubstitutionMatrix(Dictionary<string, float> matrix, bool errorIfNotInMatrix, float gapExistPenalty, float gapExtendPenalty)
    {
        this.errorWhenNotInMatrix = errorIfNotInMatrix;
        this.gapExistPenalty = gapExistPenalty;
        this.gapExtendPenalty = gapExtendPenalty;
    }

    public SubstitutionMatrix(Dictionary<string, float> matrix, bool errorIfNotInMatrix, float gapExistPenalty, float gapExtendPenalty, float highestScore, float lowestScore)
        : this(matrix, errorIfNotInMatrix, gapExistPenalty, gapExtendPenalty)
    {

        this.lowestScore = lowestScore;
        this.highestScore = highestScore;
    }

    public float GetSimilarityValue(char databaseChar, char queryChar)
    {
        string key = databaseChar.ToString() + queryChar.ToString();
        if (matrix.ContainsKey(key))
        {
            return matrix[key];
        }
        else 
        {
            return this.lowestScore;
        }
           }

  
}